using System;
using System.Collections;
using System.Collections.Generic;

using FineCollection.Intf;




namespace FineCollection.Utils
{
    /// <summary>
    /// Read-only view to another list,
    /// but the elements are presented in base type.
    /// </summary>
    public class BasingRandomListView<BT, CT> : RRandomList<BT>
        where BT : class
        where CT : class, BT
    {
        private readonly RRandomList<CT> clist;


        /// <summary>
        /// Constructs the base-type view using concrete-type list.
        /// </summary>
        /// <param name="clist">concrete-type list.</param>
        public BasingRandomListView(RRandomList<CT> clist)
        {
            if (clist == null)
                throw new NullReferenceException("Null list given.");

            this.clist = clist;
        }


        /// <summary>
        /// Count of items in the list.
        /// </summary>
        public int Count
        {
            get { return clist.Count; }
        }

        /// <summary>
        /// Checks whether the collection is empty.
        /// </summary>
        public bool IsEmpty
        {
            get { return clist.IsEmpty; }
        }

        /// <summary>
        /// Checks whether the collection has at least one item.
        /// </summary>
        public bool IsNotEmpty
        {
            get { return clist.IsNotEmpty; }
        }


        /// <summary>
        /// The first item.
        /// Raises an exception when the collection is empty.
        /// </summary>
        /// <exception cref="CollectionIsEmpty">when the collection is empty.</exception>
        public BT First
        {
            get { return clist.First; }
        }

        /// <summary>
        /// The last item.
        /// Raises an exception when the collection is empty.
        /// </summary>
        /// <exception cref="CollectionIsEmpty">when the collection is empty.</exception>
        public BT Last
        {
            get { return clist.Last; }
        }


        /// <summary>
        /// Origin index (index of the first item).
        /// </summary>
        /// <remarks>
        /// Accessible even if the collection is empty.
        /// </remarks>
        /// <seealso cref="RRandomList{T}.LastIndex"/>
        public int FirstIndex
        {
            get { return clist.FirstIndex; }
        }

        /// <summary>
        /// Index of the last item.
        /// </summary>
        /// <remarks>
        /// If the collection is empty, it is a value that less than the <see cref="RRandomList{T}.FirstIndex"/>.
        /// </remarks>
        /// <seealso cref="RRandomList{T}.FirstIndex"/>
        public int LastIndex
        {
            get { return clist.LastIndex; }
        }


        /// <summary>
        /// Represents a quick indexed access to the specified item.
        /// </summary>
        /// <remarks>
        /// The given index must be in [ FirstIndex .. LastIndex ] exclusively.
        /// </remarks>
        /// <param name="index"></param>
        /// <exception cref="CollectionIsEmpty">when the collection is empty.</exception>
        /// <exception cref="IndexOutOfBoundsException">when index is incorrect.</exception>
        /// <seealso cref="RRandomList{T}.FirstIndex"/>
        /// <seealso cref="RRandomList{T}.LastIndex"/>
        public BT this[int index]
        {
            get { return clist[index]; }
        }


        /// <summary>
        /// Creates a read-only iterator.
        /// </summary>
        /// <returns></returns>
        public RIterator<BT> TakeIterator()
        {
            RIterator<CT> cit = clist.TakeIterator();
            return new Iterator<BT,CT>(cit);
        }


        IEnumerator<BT> IEnumerable<BT>.GetEnumerator()
        {
            RIterator<CT> cit = clist.TakeIterator();
            return new Iterator<BT, CT>(cit);
        }


        IEnumerator IEnumerable.GetEnumerator()
        {
            RIterator<CT> cit = clist.TakeIterator();
            return new Iterator<BT, CT>(cit);
        }



        /// <summary>
        /// Readonly iterator.
        /// </summary>
        internal class Iterator<BTT, CTT>
            : RIterator<BTT>,
              System.Collections.Generic.IEnumerator<BTT>
            where CTT : BTT
        {
            private readonly RIterator<CTT> cit;


            internal Iterator(RIterator<CTT> cit)
            {
                this.cit = cit;
            }


            /// <summary>
            /// Resets this iterator.
            /// <para>
            /// Initially, iterator points to "begin" state - "before" the first item.
            /// </para>
            /// </summary>
            public void Reset()
            {
                cit.Reset();
            }


            /// <summary>
            /// Moves to the next element.
            /// </summary>
            /// <returns>"true" if the pointer has moved to the next item,
            ///          "false" if it has moved to behind of all items.</returns>
            public bool Next()
            {
                return cit.Next();
            }


            /// <summary>
            /// The current item (read-only access).
            /// </summary>
            public BTT Current
            {
                get { return cit.Current; }
            }

            /// <summary>
            /// Represents where the current position of the iterator.
            /// </summary>
            /// <remarks>
            /// Possible value:
            /// <list type="bullet">
            /// <item>-1: before the first item;</item>
            /// <item>0: at an item of the collection;</item>
            /// <item>+1: behind the last item.</item>
            /// </list>
            /// </remarks>
            public sbyte Where
            {
                get { return cit.Where; }
            }


            /// <summary>
            /// Clones the iterator.
            /// </summary>
            /// <returns>an exact </returns>
            public RIterator<BTT> Clone()
            {
                RIterator<CTT> cit2 = cit.Clone();
                return new Iterator<BTT,CTT>(cit2);
            }


            ///<summary>
            ///Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
            ///</summary>
            ///<filterpriority>2</filterpriority>
            public void Dispose()
            {
            }


            bool IEnumerator.MoveNext()
            {
                return cit.Next();
            }

            object IEnumerator.Current
            {
                get { throw new NotImplementedException(); }
            }
        }


    }


}
